//
// Created by konglinglong on 2020/9/24.
//

#include <fcntl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <errno.h>
#include "../../include/osal/osSelect.h"

int32_t OS_SelectInit(S_OsSelect* self, const char* pipeName)
{
    int32_t rc;
    int32_t s_pair[2];
    int32_t flags;

    memset(self, 0, sizeof(S_OsSelect));

    if (NULL == pipeName)
    {
        rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s_pair);
        if (0 != rc)
        {
            return CSP_RC_ER;
        }

        self->sendFd = s_pair[0];
        self->recvFd = s_pair[1];

        flags = fcntl(self->sendFd, F_GETFL, 0);
        fcntl(self->sendFd, F_SETFL, (flags | O_NONBLOCK));

        flags = fcntl(self->recvFd, F_GETFL, 0);
        fcntl(self->recvFd, F_SETFL, (flags | O_NONBLOCK));
    }
    else
    {
        rc = mkfifo(pipeName, S_IRWXU | S_IRWXG | S_IRWXO);
        if (0 != rc && EEXIST != errno)
        {
            return CSP_RC_ER;
        }
        self->recvFd = open(pipeName, O_RDONLY | O_NONBLOCK);
        self->sendFd = open(pipeName, O_WRONLY | O_NONBLOCK);
        if (-1 == self->recvFd || -1 == self->sendFd)
        {
            return CSP_RC_ER;
        }
        self->pipeName = strdup(pipeName);
    }

    return CSP_RC_OK;
}

int32_t OS_SelectFinal(S_OsSelect* self)
{
    close(self->sendFd);
    close(self->recvFd);

    if (self->pipeName)
    {
        unlink(self->pipeName);
        free(self->pipeName);
    }

    return CSP_RC_OK;
}

int32_t OS_SelectSend(S_OsSelect* self, S_OsSelectInd* ind)
{
    int32_t rc;

    rc = write(self->sendFd, ind, sizeof(S_OsSelectInd));
    if (sizeof(S_OsSelectInd) != rc)
    {
        return CSP_RC_ER;
    }

    return CSP_RC_OK;
}

int32_t OS_SelectRecv(S_OsSelect* self, S_OsSelectInd* ind)
{
    int32_t rc;

    rc = read(self->recvFd, ind, sizeof(S_OsSelectInd));
    if (sizeof(S_OsSelectInd) != rc)
    {
        return CSP_RC_ER;
    }

    return CSP_RC_OK;
}

int32_t OS_SelectSendByFd(int fd, S_OsSelectInd *ind)
{
    int32_t rc;

    rc = write(fd, ind, sizeof(S_OsSelectInd));
    if (sizeof(S_OsSelectInd) != rc)
    {
        return CSP_RC_ER;
    }

    return CSP_RC_OK;
}

int32_t OS_SelectRecvByFd(int fd, S_OsSelectInd *ind)
{
    int32_t rc;

    rc = read(fd, ind, sizeof(S_OsSelectInd));
    if (sizeof(S_OsSelectInd) != rc)
    {
        return CSP_RC_ER;
    }

    return CSP_RC_OK;
}

int32_t OS_SelectClear(S_OsSelect* self)
{
    S_OsSelectInd ind;
    int32_t rc;

    do
    {
        rc = recv(self->recvFd, &ind, sizeof(S_OsSelectInd), 0);
    } while (rc > 0);

    return CSP_RC_OK;
}

int32_t OS_SelectPoll(S_OsSelect *self, int32_t timeoutMs)
{
    int32_t rc;
    struct pollfd set =
        {
            .fd = self->recvFd,
            .events = POLLIN,
            .revents = 0
        };

    rc = poll(&set, 1, timeoutMs);
    if(1 == rc && (set.revents & POLLIN))
    {
        return CSP_RC_OK;
    }

    return CSP_RC_ER;
}
